package com.evil.common.mongo.service.impl;

import com.evil.common.core.enums.BaseEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.mongo.entity.Sequence;
import com.evil.common.mongo.service.SequenceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import java.util.Objects;
import java.util.function.Predicate;

/**
 * 序号自增
 *
 * @author liyang
 * @date 2025-01-06 16:31
 */
@Repository
public class SequenceServiceImpl implements SequenceService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public long generate(String seqName) {
        Query query = new Query(Criteria.where("_id").is(seqName));
        Update update = new Update().inc("seq", 1);
        Sequence counter = mongoTemplate.findAndModify(query,
                update, FindAndModifyOptions.options().returnNew(true).upsert(true),
                Sequence.class);

        return !Objects.isNull(counter) ? counter.getSeq() : 1;
    }

    @Override
    public long generate(String seqName, Predicate<Long> exist) {
        return this.generate(seqName, exist, 10);
    }

    @Override
    public long generate(String seqName, Predicate<Long> exist, int times) {
        long seq = this.generate(seqName);
        int i = 0;
        while (exist.test(seq)) {
            if (i >= times) {
                throw new BusinessException(BaseEnum.RUN_ERROR, "生成序号次数达到上限");
            }
            seq = this.generate(seqName);
        }
        return seq;
    }

    @Override
    public void clear(String seqName) {
        Query query = new Query(Criteria.where("_id").is(seqName));
        mongoTemplate.findAndRemove(query, Sequence.class);
    }
}
